package com.learm.socket.pool_v2;

import java.io.IOException;
import java.net.UnknownHostException;
import java.util.Properties;

import org.apache.log4j.Logger;


/**
 * <p>
 * Title: 这是一个连接管理器的简单实现
 * </p>
 *      这个例子是使用 BIO 的方式实现了连接池的效果。
 *      提前创建好一个 sokect连接数组。
 *
 *      getConnection 的逻辑有个问题，
 *          获取连接池中的socket连接对象时，如果目前池中的 连接都在使用中，
 *          会让线程sleep 1秒后，再调用 getConnection 方法。
 *          极限条件下回出现线程每次便利都没获取到连接。
 *          累计的时间长了 会导致调用方法产生的栈帧过多。
 *          出现栈内存溢出
 *
 * <p>
 * Description:
 * </p>
 *
 * <p>
 * Copyright: 融博技术有限公司 2012
 * </p>
 *
 * @author 袁泉锋HO174959
 * @version 1.0
 * @date Oct 15, 2012
 *
 */
public class SocketConnectionPool implements SocketConnectionPoolInterface {
    private static final Logger logger = Logger.getLogger("FrameLog");
    private Properties pro = null;
    private static SocketConnectionPoolInterface provider = null;
    private static Object object_lock = new Object();
    private String ip;
    private String port;
    /**
     *   默认的最大连接数
     */
    private int max_size = 20;
    /**
     *   默认的最小连接数
     */
    private int min_size = 10;
    /**
     *   Socket   connection池数组
     */
    private SocketConnection[] socketpool = null;
    /**
     *   构造对象的时候初始化连接池
     *   @throws   UnknownHostException   未知的主机异常
     *   @throws   IOException
     */
    private SocketConnectionPool(Properties pro) throws UnknownHostException,
            IOException {
        ip = pro.getProperty(SERVER_IP);
        port = pro.getProperty(SERVER_PORT);
        String max_size_s = pro.getProperty(MAX_SIZE);
        String min_size_s = pro.getProperty(MIN_SIZE);
        if (max_size_s != null) {
            max_size = Integer.parseInt(max_size_s);
        }
        if (min_size_s != null) {
            min_size = Integer.parseInt(min_size_s);
        }
        init(); //构造对象的时候初始化连接池
    }

    /**
     *   判断是否已经池化
     *   @return   boolean   如果池化返回ture,反之返回false
     */
    public boolean isPooled() {
        if (socketpool != null) {
            return true;
        } else {
            return false;
        }
    }

    /**
     *返回一个连接
     *   @return   a   Connection   object.
     */
    public SocketConnection getConnection() {
        SocketConnection s = null;
        for (int i = 0; i < socketpool.length; i++) {
            if (socketpool[i] != null) {
                //如果有空闲的连接，返回一个空闲连接，如果没有，继续循环
                if (socketpool[i].isFree()) {
                    s = socketpool[i];
                } else {
                    continue;
                }
            } else { //如果连接为空，证明小于最小连接数，重新生成连接
                try {
                    s = socketpool[i] = new SocketConnection(ip, Integer
                            .parseInt(port));
                } catch (Exception e) {
                    logger.error(e.getMessage());
                    //never   throw
                }
            }
        }
        /*//TODO 如果连接仍旧为空的话，则超过了最大连接数
        if (s == null) {
            try { //生成普通连接，由客户端自行关闭，释放资源，不再由连接池管理
                s = new Socket(ip, Integer.parseInt(port));
            } catch (Exception e) { //此异常永远不会抛出
            }
        }*/
        //TODO 如果连接仍旧为空的话，等待一会继续获取
        while(s == null){
            try {
                Thread.sleep(1000);
                s = this.getConnection();
            } catch (InterruptedException e) {
                e.printStackTrace();
                logger.error(e.getMessage());
            }
        }
        s.setBusy();
        return s;
    }

    /**
     *   初始化连接池
     *   @throws   UnknownHostException   主机ip找不到
     *   @throws   IOException   此端口号上无server监听
     */
    public void init() throws UnknownHostException, IOException {
        socketpool = new SocketConnection[max_size];
        for (int i = 0; i < min_size; i++) {
            socketpool[i] = new SocketConnection(ip, Integer.parseInt(port));
            logger.info(" . ");
        }
        logger.info("socketPool   init   success!");
    }

    /**
     *   重新启动连接池
     *   @throws   UnknownHostException
     *   @throws   IOException
     */
    public void restart() throws UnknownHostException, IOException {
        destroy();
        init();
    }

    /**
     *   注销此连接池
     */
    public void destroy() {
        for (int i = 0; i < socketpool.length; i++) {
            if (socketpool[i] != null) {
                SocketConnection adapter = (SocketConnection) socketpool[i];
                try {
                    adapter.destroy();
                } catch (IOException e) {
                    logger.error(e.getMessage());
                    e.printStackTrace();
                }
                logger.info(" . ");
                socketpool[i] = null;
            }
        }
        logger.info("SocketPool Destory   success!");
    }

    /**
     *   静态方法，生成此连接池实现的对象
     *   @param   pro   Properties   此连接池所需要的所有参数的封装
     *   @throws   UnknownHostException   主机无法找到
     *   @throws   IOException   与服务器无法建立连接
     *   @return   ConnectionProvider   返回父类ConnectionProvider
     */
    public static SocketConnectionPoolInterface newInstance(java.util.Properties pro)
            throws UnknownHostException, IOException {
        if (provider == null) {
            synchronized (object_lock) {
                if (provider == null) {
                    provider = new SocketConnectionPool(pro);
                }
            }
        }
        return provider;
    }

    /**
     *设置系统属性   通过封装系统properties对象来封装所需要的不同值
     *   SERVER_IP，SERVER_PORT，MAX_SIZE,MIN_SIZE等父类定义的不同的参数
     *   @param   pro   Properties   传进来的系统属性
     */
    public void setProperties(Properties pro) {
        this.pro = pro;
    }
}
